package com.zhiwei.msf.common.filter;

import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.zhiwei.msf.common.config.SecurityContext;
import com.zhiwei.msf.common.constant.DatabaseConstants;
import com.zhiwei.msf.common.util.ReflectionUtils;

/**
 * 自定义 Mybatis插件：
 * 自动设置 create_time、update_time。
 */
@Component
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MybatisUpdateInterceptor implements Interceptor {


    @SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        Object parameter = invocation.getArgs()[1];
        // org.apache.ibatis.session.defaults.DefaultSqlSession.update(java.lang.String, java.lang.Object)： 数组、集合
        if (parameter == null) {
            return invocation.proceed();
        }

        if (parameter instanceof Map) {
            Map parameterMap = (Map) parameter;

            //参数集合
            if (null != parameterMap.get("list")) {
                ((Collection) parameterMap.get("list")).forEach(obj -> this.processMetaData(obj, sqlCommandType));
            } else if (null != parameterMap.get("collection")) {
                ((Collection) parameterMap.get("collection")).forEach(obj -> this.processMetaData(obj, sqlCommandType));
            } else if (null != parameterMap.get("array")) {
                Arrays.asList((Object[]) parameterMap.get("array")).forEach(obj -> this.processMetaData(obj, sqlCommandType));
            }
        } else {
            this.processMetaData(parameter, sqlCommandType);
        }
        return invocation.proceed();
    }

    /**
     * 处理元数据
     */
    private void processMetaData(Object parameter, SqlCommandType sqlCommandType) {
        Date nowTime = new Date();
        if (SqlCommandType.UPDATE.equals(sqlCommandType)) {
            String expectedUpdateName = ReflectionUtils.getPropertyValue(parameter, DatabaseConstants.UPDATE_USER);
            ReflectionUtils.setPropertyValue(parameter, DatabaseConstants.UPDATE_TIME, nowTime);
            if (StringUtils.isEmpty(expectedUpdateName)) {
                ReflectionUtils.setPropertyValue(parameter, DatabaseConstants.UPDATE_USER, SecurityContext.getUsername());
            }
        }
        if (SqlCommandType.INSERT.equals(sqlCommandType)) {
            String expectedUpdateName = ReflectionUtils.getPropertyValue(parameter, DatabaseConstants.CREATE_USER);
            ReflectionUtils.setPropertyValue(parameter, DatabaseConstants.CREATE_TIME, nowTime);
            if (StringUtils.isEmpty(expectedUpdateName)) {
                ReflectionUtils.setPropertyValue(parameter, DatabaseConstants.CREATE_USER, SecurityContext.getUsername());
            }
        }
    }
}